#ifndef WEBRTC_BASE_CHECKS_H_
#define WEBRTC_BASE_CHECKS_H_

#include <stdint.h>

// If you for some reson need to know if DCHECKs are on, test the value of
// RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be
// defined, to either a true or a false value.)
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
#define RTC_DCHECK_IS_ON 1
#else
#define RTC_DCHECK_IS_ON 0
#endif

#ifdef __cplusplus
extern "C"
{
#endif
	void rtc_FatalMessage(const char *file, int line, const char *msg);
#ifdef __cplusplus
} // extern "C"
#endif

#ifdef __cplusplus
// C++ version.

#include <sstream>
#include <string>

namespace rtc
{

// Like a stripped-down LogMessage from logging.h, except that it aborts.
class FatalMessage
{
public:
	FatalMessage(const char *file, int line);
	// Used for RTC_CHECK_EQ(), etc. Takes ownership of the given string.
	FatalMessage(const char *file, int line, std::string *result);
	~FatalMessage();

	std::ostream &stream() { return stream_; }

private:
	void Init(const char *file, int line);

	std::ostringstream stream_;
};

// This is identical to LogMessageVoidify but in name.
class FatalMessageVoidify
{
public:
	FatalMessageVoidify() {}
	// This has to be an operator with a precedence lower than << but
	// higher than ?:
	void operator&(std::ostream &) {}
};


// Helper macro which avoids evaluating the arguments to a stream if
// the condition doesn't hold.
#define RTC_LAZY_STREAM(stream, condition) \
	!(condition) ? static_cast<void>(0) : rtc::FatalMessageVoidify() & (stream)

// The actual stream used isn't important. We reference |ignored| in the code
// but don't evaluate it; this is to avoid "unused variable" warnings (we do so
// in a particularly convoluted way with an extra ?: because that appears to be
// the simplest construct that keeps Visual Studio from complaining about
// condition being unused).
#define RTC_EAT_STREAM_PARAMETERS(ignored) \
	(true ? true : ((void)(ignored), true))  \
			? static_cast<void>(0)               \
			: rtc::FatalMessageVoidify() & rtc::FatalMessage("", 0).stream()

// RTC_CHECK dies with a fatal error if condition is not true. It is *not*
// controlled by NDEBUG or anything else, so the check will be executed
// regardless of compilation mode.
//
// We make sure RTC_CHECK et al. always evaluates their arguments, as
// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
#define RTC_CHECK(condition)                                      \
	RTC_LAZY_STREAM(rtc::FatalMessage(__FILE__, __LINE__).stream(), \
									!(condition))                    \
			<< "Check failed: " #condition << std::endl                 \
			<< "# "

  
#define RTC_DCHECK(condition) RTC_CHECK(condition)

#define RTC_UNREACHABLE_CODE_HIT false
#define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)

#define FATAL() rtc::FatalMessage(__FILE__, __LINE__).stream()


} // namespace rtc

#else // __cplusplus not defined
// C version. Lacks many features compared to the C++ version, but usage
// guidelines are the same.

#define RTC_CHECK(condition)                                             \
	do                                                                     \
	{                                                                      \
		if (!(condition))                                                    \
		{                                                                    \
			rtc_FatalMessage(__FILE__, __LINE__, "CHECK failed: " #condition); \
		}                                                                    \
	} while (0)

#define RTC_CHECK_EQ(a, b) RTC_CHECK((a) == (b))
#define RTC_CHECK_NE(a, b) RTC_CHECK((a) != (b))
#define RTC_CHECK_LE(a, b) RTC_CHECK((a) <= (b))
#define RTC_CHECK_LT(a, b) RTC_CHECK((a) < (b))
#define RTC_CHECK_GE(a, b) RTC_CHECK((a) >= (b))
#define RTC_CHECK_GT(a, b) RTC_CHECK((a) > (b))

#define RTC_DCHECK(condition)                                             \
	do                                                                      \
	{                                                                       \
		if (RTC_DCHECK_IS_ON && !(condition))                                 \
		{                                                                     \
			rtc_FatalMessage(__FILE__, __LINE__, "DCHECK failed: " #condition); \
		}                                                                     \
	} while (0)

#define RTC_DCHECK_EQ(a, b) RTC_DCHECK((a) == (b))
#define RTC_DCHECK_NE(a, b) RTC_DCHECK((a) != (b))
#define RTC_DCHECK_LE(a, b) RTC_DCHECK((a) <= (b))
#define RTC_DCHECK_LT(a, b) RTC_DCHECK((a) < (b))
#define RTC_DCHECK_GE(a, b) RTC_DCHECK((a) >= (b))
#define RTC_DCHECK_GT(a, b) RTC_DCHECK((a) > (b))

#endif // __cplusplus

#endif // WEBRTC_BASE_CHECKS_H_
